package core.reports;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import core.Amount;
import core.Barcode;
import core.CoreFacade;
import core.DataManager;
import core.Item;
import core.ItemManager;
import core.Product;
import core.ProductGroup;
import core.ProductManager;
import core.ReportConstants;
import core.StorageUnit;
import core.Unit;

public class ProductStatisticsGuideTests 
{
	private static CoreFacade model = null;
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception 
	{
		System.out.println("Starting Product Statistics Guide Tests");
		System.out.println("SETUP: Start");
		//setup code
		CoreFacade.setDBMode(false);
		DataManager.setMode(false);
		DataManager.setTestMode(true);
		
		System.out.println("SETUP: DONE");
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception 
	{
		System.out.println("CLEANUP: Start");
		
		//clean up code
		CoreFacade.destroyInstance();
		model = null;
		
		System.out.println("CLEANUP: DONE");
		System.out.println("Finished Product Statistics Guide Test");
	}
	
	@Before
	public void setUp() throws Exception 
	{
		System.out.println("-TEST: START");
		System.out.println("-TEST SETUP: START");
		
		System.out.println("-- Destroy Instance");
		CoreFacade.destroyInstance();
		model = null;
		
		System.out.println("-- Crate new Instance");
		model = CoreFacade.getInstance();
		
		System.out.println("-TEST SETUP: DONE");
	}

	@After
	public void tearDown() throws Exception 
	{
		System.out.println("-TEST CLEANUP: START");
		//clean up everything we added
		System.out.println("-- Destroy Instance");
		CoreFacade.destroyInstance();
		model = null;
		
		System.out.println("-TEST CLEANUP: DONE");
		System.out.println("-TEST: DONE");
	}
	
	@Test
	public void testUsedAverageAge()
	{
		System.out.println("\n--TEST USED AVERAGE AGE: START");
		
		//add the products needed
		StorageUnit su = null;
		
		try 
		{
			model.addStorageUnit("Test Unit1");
			List<StorageUnit> sus = model.getStorageUnits();
			
			for (int i = 0; i < sus.size(); i++)
			{
				if (sus.get(i).getName().equals("Test Unit1"))
				{
					su = sus.get(i);
					break;
				}
			}
			
			if (su == null)
			{
				fail();
			}
		} 
		catch (Exception e) 
		{
			fail();
		}
		
		Product lessThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("123"), "Batteries", 0, 0);
		Product exactly1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("122"), "Batteries", 0, 0);
		Product moreThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("121"), "Batteries", 0, 0);
		
		try 
		{
			model.addProduct(lessThan1);
			model.addProduct(exactly1);
			model.addProduct(moreThan1);
		} 
		catch (Exception e) 
		{
			fail();
		}
		//now add items
		Calendar today = new GregorianCalendar();
		Calendar yesterday = new GregorianCalendar();
		yesterday.add(Calendar.DAY_OF_MONTH, -1);
		
		Calendar many = new GregorianCalendar();
		many.add(Calendar.DAY_OF_MONTH, -4);
		
		try 
		{
			Item less1 = model.addItem(lessThan1.getBarcodeString(), yesterday, 1, su, 1, true);
			Item less2 = model.addItem(lessThan1.getBarcodeString(), today, 1, su, 2, true);
			Item less3 = model.addItem(lessThan1.getBarcodeString(), today, 1, su, 3, true);
			Item less4 = model.addItem(lessThan1.getBarcodeString(), today, 1, su, 4, true);
			Item less5 = model.addItem(lessThan1.getBarcodeString(), today, 1, su, 5, true);
			Item less6 = model.addItem(lessThan1.getBarcodeString(), today, 1, su, 6, true);
			
			Item equal1 = model.addItem(exactly1.getBarcodeString(), today, 1, su, 7, true);
			Item equal2 = model.addItem(exactly1.getBarcodeString(), today, 1, su, 8, true);
			Item equal3 = model.addItem(exactly1.getBarcodeString(), today, 1, su, 9, true);
			
			Item more1 = model.addItem(moreThan1.getBarcodeString(), many, 1, su, 10, true);
			Item more2 = model.addItem(moreThan1.getBarcodeString(), many, 1, su, 11, true);
			Item more3 = model.addItem(moreThan1.getBarcodeString(), many, 1, su, 12, true);
			
			model.removeItem(less1);
			model.removeItem(less2);
			model.removeItem(less3);
			model.removeItem(less4);
			model.removeItem(less5);
			model.removeItem(less6);
			
			model.removeItem(equal1);
			model.removeItem(equal2);
			model.removeItem(equal3);
			
			model.removeItem(more1);
			model.removeItem(more2);
			model.removeItem(more3);
		} 
		catch (Exception e) 
		{
			System.out.println("Error adding items");
			fail();
		}
		
		
		//--------------------------------------------
		System.out.println("Model Set Up");
			
		//model.createReport(ReportConstants.PRODUCT_STATISTICS_REPORT, ReportConstants.PDF_BUILDER, 3);
		ProductStatisticsGuide guide = model.testProductStatisticsGuide(3);
		
		System.out.println(guide.getUsedAverage(lessThan1.getBarcodeString()));
		
		assertTrue(guide.getUsedAverage(lessThan1.getBarcodeString()) == 1.2); //This should be 0.2
		
		assertTrue(guide.getUsedAverage(exactly1.getBarcodeString()) == 1.0);
		
		assertTrue(guide.getUsedAverage(moreThan1.getBarcodeString()) == 5.0); //This should be about 4 I believe
		
		System.out.println("--TEST USED AVERAGE AGE: DONE\n");
	}
	
	@Test
	public void testCurrentAverageAge()
	{
		System.out.println("\n--TEST CURRENT AVERAGE AGE: START");
		
		//add the products needed
		StorageUnit su = null;
		
		try 
		{
			model.addStorageUnit("Test Unit1");
			List<StorageUnit> sus = model.getStorageUnits();
			
			for (int i = 0; i < sus.size(); i++)
			{
				if (sus.get(i).getName().equals("Test Unit1"))
				{
					su = sus.get(i);
					break;
				}
			}
			
			if (su == null)
			{
				fail();
			}
		} 
		catch (Exception e) 
		{
			fail();
		}
		
		Product lessThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("123"), "Batteries", 0, 0);
		Product exactly1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("122"), "Batteries", 0, 0);
		Product moreThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("121"), "Batteries", 0, 0);
		
		try 
		{
			model.addProduct(lessThan1);
			model.addProduct(exactly1);
			model.addProduct(moreThan1);
		} 
		catch (Exception e) 
		{
			fail();
		}
		 
		//now add items
		Calendar today = new GregorianCalendar();
		
		Calendar fewHrs = new GregorianCalendar();
		fewHrs.add(Calendar.HOUR, -12);
		
		Calendar yesterday = new GregorianCalendar();
		yesterday.add(Calendar.DAY_OF_MONTH, -1);
		
		Calendar many = new GregorianCalendar();
		many.add(Calendar.DAY_OF_MONTH, -4);
		
		try 
		{
			Item less1 = model.addItem(lessThan1.getBarcodeString(), fewHrs, 1, su, 1, true);
			Item less2 = model.addItem(lessThan1.getBarcodeString(), fewHrs, 1, su, 2, true);
			Item less3 = model.addItem(lessThan1.getBarcodeString(), fewHrs, 1, su, 3, true);
			
			Item equal1 = model.addItem(exactly1.getBarcodeString(), today, 1, su, 4, true);
			Item equal2 = model.addItem(exactly1.getBarcodeString(), today, 1, su, 5, true);
			Item equal3 = model.addItem(exactly1.getBarcodeString(), today, 1, su, 6, true);
			
			Item more1 = model.addItem(moreThan1.getBarcodeString(), many, 1, su, 7, true);
			Item more2 = model.addItem(moreThan1.getBarcodeString(), many, 1, su, 8, true);
			Item more3 = model.addItem(moreThan1.getBarcodeString(), many, 1, su, 9, true);
		} 
		catch (Exception e) 
		{
			System.out.println("--Error adding items");
			fail();
		}
		
		
		//--------------------------------------------
		System.out.println("--Model Set Up");
		
		ProductStatisticsGuide guide = model.testProductStatisticsGuide(3);
		
		System.out.println(guide.getAvgAge(lessThan1.getBarcodeString()));
		System.out.println(guide.getAvgAge(exactly1.getBarcodeString()));
		System.out.println(guide.getAvgAge(moreThan1.getBarcodeString()));
		
		assertTrue(guide.getAvgAge(lessThan1.getBarcodeString()) == 1.0); //This should be 0.0
		
		assertTrue(guide.getAvgAge(exactly1.getBarcodeString()) == 1.0); //This should be 0.0
		
		assertTrue(guide.getAvgAge(moreThan1.getBarcodeString()) == 5.0); //This should be 0.0
		
		System.out.println("--TEST CURRENT AVERAGE AGE: DONE\n");
	}
	
	@Test
	public void testReportBoundries()
	{
		System.out.println("\n--TEST REPORT BOUNDRIES: START");
		
		//add the products needed
				StorageUnit su = null;
				
				try 
				{
					model.addStorageUnit("Test Unit1");
					List<StorageUnit> sus = model.getStorageUnits();
					
					for (int i = 0; i < sus.size(); i++)
					{
						if (sus.get(i).getName().equals("Test Unit1"))
						{
							su = sus.get(i);
							break;
						}
					}
					
					if (su == null)
					{
						fail();
					}
				} 
				catch (Exception e) 
				{
					fail();
				}
				
				Product lessThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("123"), "Batteries", 0, 0);
				Product exactly1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("122"), "Batteries", 0, 0);
				Product moreThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("121"), "Batteries", 0, 0);
				
				try 
				{
					model.addProduct(lessThan1);
					model.addProduct(exactly1);
					model.addProduct(moreThan1);
				} 
				catch (Exception e) 
				{
					fail();
				}
				
				//now add items
				Calendar today = new GregorianCalendar();
				
				Calendar dayBefore = new GregorianCalendar();
				dayBefore.add(Calendar.MONTH, -3);
				dayBefore.add(Calendar.DAY_OF_MONTH, -1);
				
				Calendar Middle = new GregorianCalendar();
				Middle.add(Calendar.MONTH, -1);
				Middle.add(Calendar.DAY_OF_MONTH, -14);
				
				try 
				{
					Item less1 = model.addItem(lessThan1.getBarcodeString(), dayBefore, 1, su, 1, true);
					Item less2 = model.addItem(lessThan1.getBarcodeString(), dayBefore, 1, su, 2, true);
					Item less3 = model.addItem(lessThan1.getBarcodeString(), dayBefore, 1, su, 3, true);
					
					Item equal1 = model.addItem(exactly1.getBarcodeString(), Middle, 1, su, 4, true);
					Item equal2 = model.addItem(exactly1.getBarcodeString(), Middle, 1, su, 5, true);
					Item equal3 = model.addItem(exactly1.getBarcodeString(), Middle, 1, su, 6, true);
					
					Item more1 = model.addItem(moreThan1.getBarcodeString(), today, 1, su, 7, true);
					Item more2 = model.addItem(moreThan1.getBarcodeString(), today, 1, su, 8, true);
					Item more3 = model.addItem(moreThan1.getBarcodeString(), today, 1, su, 9, true);
					
					
					model.removeItem(less1);
					model.removeItem(less2);
					model.removeItem(less3);
					
					model.removeItem(equal1);
					model.removeItem(equal2);
					model.removeItem(equal3);
					
					model.removeItem(more1);
					model.removeItem(more2);
					model.removeItem(more3);
				}
				catch (Exception e) 
				{
					System.out.println("--Error adding items");
					fail();
				}
				
				
				//--------------------------------------------
				System.out.println("--Model Set Up");
				
				//currentAge test
				ProductStatisticsGuide guide = model.testProductStatisticsGuide(3);
				
				System.out.println(guide.getUsedAverage(lessThan1.getBarcodeString()));
				System.out.println(guide.getUsedAverage(exactly1.getBarcodeString()));
				System.out.println(guide.getUsedAverage(moreThan1.getBarcodeString()));
				
				/*System.out.println(guide.getAvgAge(lessThan1.getBarcodeString()));
				System.out.println(guide.getAvgAge(exactly1.getBarcodeString()));
				System.out.println(guide.getAvgAge(moreThan1.getBarcodeString()));
				
				assertTrue(guide.getAvgAge(lessThan1.getBarcodeString()) == 0);
				assertTrue(guide.getAvgAge(exactly1.getBarcodeString()) == 0);
				assertTrue(guide.getAvgAge(moreThan1.getBarcodeString()) == 0);*/
				
				assertTrue(guide.getUsedAverage(lessThan1.getBarcodeString()) == 93);
				assertTrue(guide.getUsedAverage(exactly1.getBarcodeString()) == 45);
				assertTrue(guide.getUsedAverage(moreThan1.getBarcodeString()) == 1);
				
				System.out.println(guide.getSupplyAvg(lessThan1.getBarcodeString()));
				System.out.println(guide.getSupplyAvg(exactly1.getBarcodeString()));
				System.out.println(guide.getSupplyAvg(moreThan1.getBarcodeString()));
				
				assertTrue(guide.getSupplyAvg(lessThan1.getBarcodeString()) == 0);	
				assertTrue(guide.getSupplyAvg(exactly1.getBarcodeString()) == 0); 
				assertTrue(guide.getSupplyAvg(moreThan1.getBarcodeString()) == 0); 
		
		System.out.println("--TEST REPORT BOUNDRIES: DONE\n");
	}
	
	@Test
	public void testLengthOfReportingPeriod()
	{
		System.out.println("\n--TEST LENGTH OF REPORTING PERIOD: START");
		
		//add the products needed
		StorageUnit su = null;
		
		try 
		{
			model.addStorageUnit("Test Unit1");
			List<StorageUnit> sus = model.getStorageUnits();
			
			for (int i = 0; i < sus.size(); i++)
			{
				if (sus.get(i).getName().equals("Test Unit1"))
				{
					su = sus.get(i);
					break;
				}
			}
			
			if (su == null)
			{
				fail();
			}
		} 
		catch (Exception e) 
		{
			fail();
		}
		
		Product lessThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("123"), "Batteries", 0, 0);
		Product exactly1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("122"), "Batteries", 0, 0);
		Product moreThan1 = ProductManager.createProduct(new Amount(Unit.count,1), new Barcode("121"), "Batteries", 0, 0);
		
		try 
		{
			model.addProduct(lessThan1);
			model.addProduct(exactly1);
			model.addProduct(moreThan1);
		} 
		catch (Exception e) 
		{
			fail();
		}
		
		//now add items
		Calendar today = new GregorianCalendar();
		
		Calendar dayBefore = new GregorianCalendar();
		dayBefore.add(Calendar.MONTH, -3);
		dayBefore.add(Calendar.DAY_OF_MONTH, -1);
		
		Calendar Middle = new GregorianCalendar();
		Middle.add(Calendar.MONTH, -50);
		Middle.add(Calendar.DAY_OF_MONTH, -14);
		
		try 
		{
			Item less1 = model.addItem(lessThan1.getBarcodeString(), dayBefore, 1, su, 1, true);
			Item less2 = model.addItem(lessThan1.getBarcodeString(), dayBefore, 1, su, 2, true);
			Item less3 = model.addItem(lessThan1.getBarcodeString(), dayBefore, 1, su, 3, true);
			
			Item equal1 = model.addItem(exactly1.getBarcodeString(), Middle, 1, su, 4, true);
			Item equal2 = model.addItem(exactly1.getBarcodeString(), Middle, 1, su, 5, true);
			Item equal3 = model.addItem(exactly1.getBarcodeString(), Middle, 1, su, 6, true);
			
			Item more1 = model.addItem(moreThan1.getBarcodeString(), today, 1, su, 7, true);
			Item more2 = model.addItem(moreThan1.getBarcodeString(), today, 1, su, 8, true);
			Item more3 = model.addItem(moreThan1.getBarcodeString(), today, 1, su, 9, true);
			
			
			model.removeItem(less1);
			model.removeItem(less2);
			model.removeItem(less3);
			
			model.removeItem(equal1);
			//model.removeItem(equal2);
			model.removeItem(equal3);
			
			//model.removeItem(more1);
			model.removeItem(more2);
			//model.removeItem(more3);
		}
		catch (Exception e) 
		{
			System.out.println("--Error adding items");
			fail();
		}
		
		
		//--------------------------------------------
		System.out.println("--Model Set Up");
		
		ProductStatisticsGuide guide1 = model.testProductStatisticsGuide(1);
		ProductStatisticsGuide guide5 = model.testProductStatisticsGuide(5);
		ProductStatisticsGuide guide100 = model.testProductStatisticsGuide(100);
		
		assertTrue(guide1.numNodes() == 3);
		assertTrue(guide5.numNodes() == 3);
		assertTrue(guide100.numNodes() == 3);
		
		System.out.println("guide1= " + guide1.numUsedNodes());
		System.out.println("guide2= " + guide5.numUsedNodes());
		System.out.println("guide3= " + guide100.numUsedNodes());
		
		assertTrue(guide1.numUsedNodes() == 2);
		assertTrue(guide5.numUsedNodes() == 2);
		assertTrue(guide100.numUsedNodes() == 2);
		
		//Test HTML Builder
		String name = model.createReport(ReportConstants.PRODUCT_STATISTICS_REPORT, ReportConstants.HTML_BUILDER, 25);
		
		assertTrue(name.substring(name.length()-5).equals(".html"));
		
		System.out.println("--TEST LENGTH OF REPORTING PERIOD: DONE\n");
	}
}
